package com.hitqz.robot.biz.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.hitqz.robot.api.business.entity.TicketsEntity;
import com.hitqz.robot.api.business.entity.TicketsTaskEntity;
import com.hitqz.robot.api.business.params.QueryTasksTicketsParams;
import com.hitqz.robot.api.business.vo.TicketsTaskVo;
import com.hitqz.robot.api.business.vo.TicketsVo;
import com.hitqz.robot.biz.service.TicketsService;
import com.hitqz.robot.biz.service.TicketsTaskService;
import com.hitqz.robot.common.core.util.R;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.http.codec.ServerSentEvent;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.time.Duration;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author xupkun
 * @date 2024/6/13
 */

@RestController
@AllArgsConstructor
@RequestMapping("/tickets")
@Tag(name = "工单管理")
@Slf4j
public class TicketsController {


    private final ExecutorService executor = Executors.newCachedThreadPool();

    private final TicketsService ticketsService;

    private final TicketsTaskService ticketsTaskService;

    private static final String EVENT_NAME = "recent_tickets\n";
    private static final int TICKET_COUNT = 5;
    private static final Duration INTERVAL_DURATION = Duration.ofSeconds(1);
    private static final Duration TIMEOUT_DURATION = Duration.ofSeconds(5);


    @PostMapping("/page")
    @Operation(summary = "分页查询工单列表")
    public R<Page<TicketsVo>> page(@RequestBody QueryTasksTicketsParams queryTicketsParams) {
        LambdaQueryWrapper<TicketsEntity> wrapper = Wrappers.lambdaQuery();
        Page page = new Page(queryTicketsParams.getCurrent(), queryTicketsParams.getSize());
        wrapper.like(StrUtil.isNotBlank(queryTicketsParams.getContent()), TicketsEntity::getName, queryTicketsParams.getContent());
        if (StrUtil.isNotBlank(queryTicketsParams.getStartTime())) {
            wrapper.gt(TicketsEntity::getCreateTime, queryTicketsParams.getStartTime());
        }
        if (StrUtil.isNotBlank(queryTicketsParams.getEndTime())) {
            wrapper.gt(TicketsEntity::getCreateTime, queryTicketsParams.getEndTime());
        }
        wrapper.orderByDesc(TicketsEntity::getCreateTime);
        Page<TicketsEntity> data = ticketsService.page(page, wrapper);
        Page<TicketsVo> voPage = new Page<>();
        BeanUtil.copyProperties(data, voPage, false);
        List<TicketsVo> vos = Lists.newArrayList();
        for (TicketsEntity ticket: data.getRecords()) {
            TicketsVo vo = new TicketsVo();
            BeanUtil.copyProperties(ticket, vo, false);
            vos.add(vo);
        }
        voPage.setRecords(vos);
        return R.ok(voPage);
    }


    @PostMapping(value = "pageTasks")
    @Operation(summary = "查询工单任务")
    public R<Page<TicketsTaskVo>> pageTasks(@RequestBody QueryTasksTicketsParams params) {
        LambdaQueryWrapper<TicketsTaskEntity> wrapper = Wrappers.lambdaQuery();
        Page page = new Page(params.getCurrent(), params.getSize());
        wrapper.eq(TicketsTaskEntity::getTicketsId, params.getTicketsId());
        wrapper.like(TicketsTaskEntity::getContent, params.getContent());
        Page<TicketsTaskEntity> data = ticketsTaskService.page(page, wrapper);
        List<TicketsTaskVo> vos = Lists.newArrayList();
        for (TicketsTaskEntity task : data.getRecords()) {
            TicketsTaskVo vo = new TicketsTaskVo();
            BeanUtil.copyProperties(task, vo, false);
            vos.add(vo);
        }
        Page<TicketsTaskVo> taskVoPage = new Page<>();
        BeanUtil.copyProperties(data, taskVoPage);
        taskVoPage.setRecords(vos);
        return R.ok(taskVoPage);
    }


    //@GetMapping(value = "recentTickets", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    //@Operation(summary = "最近的任务数据",description = "客户端采用EventSource进行连接")
    //public Flux<ServerSentEvent<R<List<TicketsVo>>>> recentTickets(
    //) {
    //    return Flux.interval(Duration.ofSeconds(1))
    //            .flatMap(sequence -> Mono.fromCallable(() -> ticketsService.findRecentTickets(5))
    //                            .map(tickets -> ServerSentEvent.<R<List<TicketsVo>>>builder()
    //                                    .id(String.valueOf(sequence))
    //                                    .event("recent_tickets\n")
    //                                    .data(R.ok(ticketsService.findRecentTickets(5)))
    //                                    .build())
    //                            .onErrorResume(e -> Mono.just(ServerSentEvent.<R<List<TicketsVo>>>builder()
    //                                    .id(String.valueOf(sequence))
    //                                    .event("recent_tickets\n")
    //                                    .data(R.ok(List.of()))
    //                                    .build()))
    //                            .doOnCancel(()-> {
    //
    //                            })
    //                            .doOnError((error)-> {
    //                                log.info("recent_tickets error:{}", error.getMessage());
    //                            })
    //
    //                            .timeout(Duration.ofSeconds(5), Mono.just(ServerSentEvent.<R<List<TicketsVo>>>builder()
    //                                    .id(String.valueOf(sequence))
    //                                    .event("recent_tickets\n")
    //                                    .data(R.ok(List.of()))
    //                                    .build())),
    //                    1);
    //}



    @GetMapping(value = "recentTickets", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    @Operation(summary = "最近的任务数据", description = "客户端采用EventSource进行连接")
    public Flux<ServerSentEvent<R<List<TicketsVo>>>> recentTickets() {
        return Flux.interval(INTERVAL_DURATION)
                .flatMap(sequence -> buildServerSentEvent(sequence), 1)
                .doOnCancel(() -> log.info("Subscription cancelled"))
                .doOnError(error -> log.error("Error in recentTickets: {}", error.getMessage()))
                .doOnSubscribe(subscription -> log.info("Subscription started"));
    }

    private Mono<ServerSentEvent<R<List<TicketsVo>>>> buildServerSentEvent(long sequence) {
        return Mono.fromCallable(() -> ticketsService.findRecentTickets(TICKET_COUNT))
                .map(tickets -> createEvent(sequence, tickets))
                .onErrorResume(e -> {
                    log.error("Error fetching recent tickets: {}", e.getMessage());
                    return Mono.just(createEmptyEvent(sequence));
                })
                .timeout(TIMEOUT_DURATION, Mono.just(createEmptyEvent(sequence)));
    }

    private ServerSentEvent<R<List<TicketsVo>>> createEvent(long sequence, List<TicketsVo> tickets) {
        return ServerSentEvent.<R<List<TicketsVo>>>builder()
                .id(String.valueOf(sequence))
                .event(EVENT_NAME)
                .data(R.ok(tickets))
                .build();
    }

    private ServerSentEvent<R<List<TicketsVo>>> createEmptyEvent(long sequence) {
        return ServerSentEvent.<R<List<TicketsVo>>>builder()
                .id(String.valueOf(sequence))
                .event(EVENT_NAME)
                .data(R.ok(List.of()))
                .build();
    }

}
